package com.hxh.wechat.voide;

import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.EditText;

import androidx.appcompat.app.AppCompatActivity;

import com.google.gson.Gson;
import com.hxh.wechat.R;
import com.hxh.wechat.constant.GlobalConstant;
import com.hxh.wechat.voide.constant.SignalConstant;

import org.json.JSONException;
import org.json.JSONObject;
import org.webrtc.AudioTrack;
import org.webrtc.CameraVideoCapturer;
import org.webrtc.EglBase;
import org.webrtc.IceCandidate;
import org.webrtc.MediaStream;
import org.webrtc.PeerConnection;
import org.webrtc.RendererCommon;
import org.webrtc.SessionDescription;
import org.webrtc.SurfaceViewRenderer;
import org.webrtc.VideoTrack;

import java.util.HashMap;
import java.util.Map;

public class CallVideoActivity extends AppCompatActivity implements SignalingDelegate {

    SurfaceViewRenderer localSurfaceView;
    SurfaceViewRenderer remoteSurfaceView;

    VideoTrack videoTrack;
    AudioTrack audioTrack;

    MediaCapturer mediaCapturer;
    static Signaling signaling;

    Map<String, PConnection> peerConnections = new HashMap<>();
    EglBase mRootEglBase;

    String sessionId;
    static String localUserId;
    static String TAG = "CallVideoActivity";
    static String remoteUserId;

    static String roomId;

    public static void goChatVideo(Context context, String uid, String roomId) {
        Intent intent = new Intent(context, CallVideoActivity.class);
        Bundle bundle = new Bundle();
        bundle.putString("uid", uid);
        bundle.putString("roomId", roomId);
        // 将 contact 其他需要传递的属性也添加到 Bundle 中
        intent.putExtras(bundle);
        context.startActivity(intent);
        signaling = new Signaling("ws://"+ GlobalConstant.URL+":8099/ws", localUserId);
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_camera);
        //获取 双方id 拼凑一个独一房间号
        roomId = getIntent().getStringExtra("roomId");
        localUserId = getIntent().getStringExtra("uid");


        signaling.delegate = this;
        mRootEglBase = EglBase.create();
        mediaCapturer = new MediaCapturer(getBaseContext(), mRootEglBase);

        localSurfaceView = findViewById(R.id.LocalSurfaceView);
        localSurfaceView.init(mRootEglBase.getEglBaseContext(), null);
        localSurfaceView.setScalingType(RendererCommon.ScalingType.SCALE_ASPECT_FILL);
        localSurfaceView.setZOrderMediaOverlay(true);

        try {
            mediaCapturer.initCamera(getBaseContext());
            videoTrack = mediaCapturer.createVideoTrack(getBaseContext(),
                    localSurfaceView, mRootEglBase.getEglBaseContext());
            audioTrack = mediaCapturer.createAudioTrack();
        } catch (Exception e) {
            e.printStackTrace();
        }

        remoteSurfaceView = findViewById(R.id.RemoteSurfaceView);
        remoteSurfaceView.init(mRootEglBase.getEglBaseContext(), null);
        remoteSurfaceView.setScalingType(RendererCommon.ScalingType.SCALE_ASPECT_FILL);
        remoteSurfaceView.setMirror(true);
        remoteSurfaceView.setVisibility(View.VISIBLE);
        try {
            startCall();
        } catch (JSONException e) {
            throw new RuntimeException(e);
        }
        findViewById(R.id.switch_camera_tv).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                mediaCapturer.mCameraVideoCapturer.switchCamera(new CameraVideoCapturer.CameraSwitchHandler() {
                    @Override
                    public void onCameraSwitchDone(boolean b) {

                    }

                    @Override
                    public void onCameraSwitchError(String s) {

                    }
                });
            }
        });
        findViewById(R.id.loundspeaker_tv).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                audioTrack.setEnabled(!audioTrack.enabled());
            }
        });
        findViewById(R.id.videoQuit).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                finish();
            }
        });
    }

    //加入房间
    void doJoin() {
        //创建连接对象
        createPeerConnection(localUserId);
        System.out.println("加入房间" + roomId);
        Map<String, Object> jsonMsg = new HashMap<>();
        jsonMsg.put("cmd", "join");
        jsonMsg.put("roomId", roomId);
        jsonMsg.put("uid", localUserId);
        String message = new Gson().toJson(jsonMsg);
        signaling.send(message);
    }

    /**
     * 启动
     *
     * @throws JSONException
     */
    void startCall() throws JSONException {
        doJoin();
    }

    //创建offer
    void doOffer() {
        PConnection pc = peerConnections.get(localUserId);
        pc.createOffer(new PConnection.CompletionHandler() {
            @Override
            public void success(SessionDescription sessionDescription) {
                Log.d(TAG, "设置 Description  成功");
                JSONObject jsonMsg = new JSONObject();
                try {
                    jsonMsg.put("cmd", "offer");
                    jsonMsg.put("roomId", roomId);
                    jsonMsg.put("uid", localUserId);
                    jsonMsg.put("remoteUid", remoteUserId);
                    jsonMsg.put("msg", new Gson().toJson(sessionDescription));
                    String message = jsonMsg.toString();
                    signaling.send(message);
                } catch (JSONException e) {
                    e.printStackTrace();
                }
            }
        });
    }

    void doAnswer() {
        //创建连接对象
        PConnection pc = peerConnections.get(localUserId);
        pc.createAnswer(new PConnection.CompletionHandler() {
            @Override
            public void success(SessionDescription sessionDescription) {
                JSONObject jsonMsg = new JSONObject();
                try {
                    jsonMsg.put("cmd", "answer");
                    jsonMsg.put("roomId", roomId);
                    jsonMsg.put("uid", localUserId);
                    jsonMsg.put("remoteUid", remoteUserId);
                    jsonMsg.put("msg", new Gson().toJson(sessionDescription));
                    String message = jsonMsg.toString();
                    signaling.send(message);
                } catch (JSONException e) {
                    e.printStackTrace();
                }
            }
        });
    }


    PConnection createPeerConnection(String peerId) {
        PConnection pc = new PConnection();
        pc.createPeerConnection(mediaCapturer.mPeerConnectionFactory, audioTrack, videoTrack);
        peerConnections.put(peerId, pc);
        pc.callback = new PConnection.Callback() {
            @Override
            public void onAddStream(PeerConnection peerConnection, MediaStream mediaStream) {
                VideoTrack remoteVideoTrack = mediaStream.videoTracks.get(0);
                remoteVideoTrack.setEnabled(true);
                remoteVideoTrack.addSink(remoteSurfaceView);
            }

            @Override
            public void onIceCandidate(PeerConnection peerConnection, IceCandidate candidate) {
                Log.i("收集候选者后", "start");
                JSONObject jsonMsg = new JSONObject();
                try {
                    jsonMsg.put("cmd", "candidate");
                    jsonMsg.put("roomId", roomId);
                    jsonMsg.put("uid", localUserId);
                    jsonMsg.put("remoteUid", remoteUserId);
                    jsonMsg.put("msg", new Gson().toJson(candidate));
                    String message = jsonMsg.toString();
                    signaling.send(message);
                } catch (JSONException e) {
                    e.printStackTrace();
                }
            }
        };
        return pc;
    }

    @Override
    public void onMessage(JSONObject jsonMsg) throws JSONException {
        String type = jsonMsg.getString("cmd");
        switch (type) {
            case SignalConstant.SIGNAL_TYPE_NEW_PEER:
                handleRemoteNewPeer(jsonMsg);
                break;
            case SignalConstant.SIGNAL_TYPE_RESP_JOIN:
                handleResponseJson(jsonMsg);
                break;
            case SignalConstant.SIGNAL_TYPE_LEAVE:
                handleLeave(jsonMsg);
                break;
            case SignalConstant.SIGNAL_TYPE_PEER_LEAVE:
                handleRemotePeerLeave(jsonMsg);
                break;
            case SignalConstant.SIGNAL_TYPE_OFFER:
                handleRemoteOffer(jsonMsg);
                break;
            case SignalConstant.SIGNAL_TYPE_ANSWER:
                handleRemoteAnswer(jsonMsg);
                break;
            case SignalConstant.SIGNAL_TYPE_CANDIDATE:
                handleRemoteCandidate(jsonMsg);
                break;
            default:
                // Handle default case here
                break;
        }
    }

    void handleRemoteNewPeer(JSONObject message) {
        String remoteUid = null;
        try {
            remoteUid = message.getString("remoteUid");
            Log.d("tag", "handleRemoteNewPeer Uid" + remoteUid);
            remoteUserId = remoteUid;
        } catch (JSONException e) {
            throw new RuntimeException(e);
        }
    }

    void handleResponseJson(JSONObject message) {
        String remoteUid = null;
        try {
            remoteUid = message.getString("remoteUid");
            Log.d("tag", "handleResponseJson Uid" + remoteUid);
            remoteUserId = remoteUid;
            doOffer();
        } catch (JSONException e) {
            throw new RuntimeException(e);
        }
    }

    void handleLeave(JSONObject message) {

    }

    void handleRemotePeerLeave(JSONObject message) {

    }

    void handleRemoteOffer(JSONObject message) {
        PConnection pConnection = peerConnections.get(localUserId);
        try {
            pConnection.onRemote(message);
            doAnswer();
        } catch (JSONException e) {
            throw new RuntimeException(e);
        }
    }

    void handleRemoteAnswer(JSONObject message) throws JSONException {
        PConnection pc = peerConnections.get(localUserId);
        pc.onRemote(message);
    }


    void handleRemoteCandidate(JSONObject message) throws JSONException {
        PConnection pc = peerConnections.get(localUserId);
        Log.d(TAG, "handleRemoteCandidate");
        IceCandidate candidate = new Gson().fromJson(message.getString("msg"), IceCandidate.class);
        if (pc != null) {
            pc.peerConnection.addIceCandidate(candidate);
        }
    }
}
